package toolsUseCourse.useUtilClass.rtutil;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 参考：
 * https://www.jianshu.com/p/5b97e86aa1ee
 */
public class UseStreamMethod {

//    jdk1.8 新特性Stream API,支持流式编程
    /*
    System.out::println
    等价于
    s -> System.out.println(s)
    note：这里的s不是固定的，只是个代号，代表当前元素的每一个子元素，
    可以把s换为，index或者item或者element，等...，有什么不能换的我还不知道，没遇见过

    Integer::parseInt
    等价于
    s-> Integer.parseInt(s)


    .filter(a -> a % 2 == 0)
       等价于
    .filter(a -> {
        System.out.println("@1");
        return  a % 2 == 0;
    })

    * */

//
    public static void castOtherTypetoStream(Object object){

//        根据Collection获取流
//        list
        List<String> list = new ArrayList<>();
        Stream<String> st1 = list.stream();

//        set
        Set<String> set = new HashSet<>();
        Stream<String> st2 = set.stream();

//        vector
        Vector<String> vector = new Vector<>();
        Stream<String> st3 = vector.stream();

//        根据Map获取流
        Map<String,String> map = new HashMap<>();

        Stream<String> keyStream = map.keySet().stream();

        Stream<String> valueStream = map.values().stream();

        Stream<Map.Entry<String,String>> entryStream = map.entrySet().stream();

//        根据数组获取流
        String[] array = {"张三","李四","王二","麻子"};
        Stream<String> st4 = Stream.of(array);

    }

    public static void castStreamToOtherType() {

    }

    public static void getParallelStream() {
        Collection<String> coll = new ArrayList<>();

        Stream<String> ParallelStream1 = coll.parallelStream();
        Stream<Integer> ParallelStram2 = Stream.of(100,200,300,400,500).parallel();
    }

    public static void useForEach() {
//        相当于
        Stream<String> st1 = Stream.of("张三","李四","王二","麻子");
//        st1.forEach(System.out::println);
        // 等同于如下代码
        st1.forEach(s -> System.out.println(s));
    }

    public static void useFilter() {
        Stream.of("张三","李四","王二","麻子","张三丰","张无忌")
                .filter(s -> s.startsWith("张")) // 只留下，第一个字符为“张”的元素（不为“张”的元素过滤掉了）
                .forEach(s -> System.out.println(s));
    }

    public static void useMap() {
//        将流中的元素映射到另一个流中
        Stream.of("1","2","3","4","5","6")
                .map(Integer::parseInt)
                .forEach(s -> System.out.println(s*10));
        Stream.of("1","2","3","4","5","6")
                .map(element -> Integer.parseInt(element))
                .forEach(s -> System.out.println(s*10));
    }

    public static void useCount() {
        //        count 统计个数
        System.out.println(Stream.of("1", "2", "3", "4", "5", "6")
                .map(Integer::parseInt)
                .count());
        //        count 统计个数
        System.out.println(Stream.of("1", "2", "3", "4", "5", "6")
                .count());
    }

    public static void useLimit() {
//        Stream<T> limit(long maxSize)
//        测：0,如果传入的参数maxSize大于数据类型的size,
        Stream.of("1", "2", "3", "4", "5", "6")
                .limit(8)
                .forEach(System.out::println);
    }

    public static void useSkip() {
//        Stream<T> skip(long n);
//        去除前 n 个元素
        Stream.of("1", "2", "3", "4", "5", "6")
                .skip(5)
                .forEach(System.out::println);
    }

    public static void useConcat() {
//        public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
        Stream.concat(
                Stream.of("1", "2", "3", "4", "5", "6"),
                Stream.of("7")
        ).forEach(System.out::println);
    }

    public static void orderOfExecution() {
        ArrayList<String> arr = new ArrayList<>();
        arr.add("张翠山");
        arr.add("张无忌");
        arr.add("张大侠");
        arr.add("张三丰");
        arr.add("张傻屌");

        arr.stream().filter(s -> {
            System.out.println("@1");// 1
            return s.startsWith("张");// 2
        }).filter(s -> {
            System.out.println("#2");// 3
            return s.length() == 3;// 4
        }).forEach(System.out::println);

//        执行顺序是：1 2 3 4 1 2 3 4 ... 1 2 3 4
//        不是：1 2 ... 1 2 3 4 ... 3 4
//        note: 可以在这四个地方打断点

    }

    public static void compareParallelStreamWithSingleThreadStream() {
        int n = 1000000;
        Integer[] arr = new Integer[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }

        ArrayList<Integer> first = new ArrayList<>();
        ArrayList<Integer> second = new ArrayList<>();

        long start1 = System.currentTimeMillis();
        Stream.of(arr)
                .filter(a -> a % 2 == 0)
                .filter(b -> b % 3 == 0)
                .filter(c -> c % 5 == 0)
                .filter(d -> d % 7 == 0)
                .forEach(first::add);
        long end1 = System.currentTimeMillis();
        System.out.println("单线程流耗时：" + (end1 - start1) + "ms");

        long start2 = System.currentTimeMillis();
        Stream.of(arr).parallel()
                .filter(a -> a % 2 == 0)
                .filter(b -> b % 3 == 0)
                .filter(c -> c % 5 == 0)
                .filter(d -> d % 7 == 0)
                .forEach(second::add);
        long end2 = System.currentTimeMillis();
        System.out.println("并行流耗时：" + (end2 - start2) + "ms");
        /*
            单线程流耗时：78ms
            并行流耗时：34ms
        * */

//        foreach在并行
    }


    public static void orderOfParallelStream() {
        int n = 10;
        Integer[] arr = new Integer[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }

        ArrayList<Integer> first = new ArrayList<>();
        ArrayList<Integer> second = new ArrayList<>();

        long start1 = System.currentTimeMillis();
        Stream.of(arr)
                .filter(a -> {
                    System.out.println("@1");
                    return  a % 2 == 0;
                })
                .filter(b -> {
                    System.out.println("@2");
                    return b % 3 == 0;
                })
                .filter(c -> {
                    System.out.println("@3");
                    return c % 5 == 0;
                })
                .filter(d -> {
                    System.out.println("@4");
                    return d % 7 == 0;
                })
                .forEach(first::add);
        long end1 = System.currentTimeMillis();
        System.out.println("单线程流耗时：" + (end1 - start1) + "ms");

        long start2 = System.currentTimeMillis();
        Stream.of(arr).parallel()
                .filter(a -> {
                    System.out.println("#1");
                    return  a % 2 == 0;
                })
                .filter(b -> {
                    System.out.println("#2");
                    return b % 3 == 0;
                })
                .filter(c -> {
                    System.out.println("#3");
                    return c % 5 == 0;
                })
                .filter(d -> {
                    System.out.println("#4");
                    return d % 7 == 0;
                })
                .forEach(second::add);
        long end2 = System.currentTimeMillis();
        System.out.println("并行流耗时：" + (end2 - start2) + "ms");
    }

    public static void useLimitCombinedWithSkip () {
        /*
        * tips:
skip(m)用在 limit(n) 前面时，先去除前 m 个元素再返回剩余元素的前 n 个元素。
limit(n) 用在 skip(m) 前面时，先返回前 n 个元素再在剩余的 n 个元素中去除 m 个元素。*/
        Stream.of("1", "2", "3", "4", "5", "6")
                .skip(3).limit(2)
                .forEach(System.out::println);
    }

    public static void useDistinct() {
        /*
        * 需要先定义好 equals 方法，不然类似[Person{name='jack', age=20}, Person{name='jack', age=20}] 这样的情况是不会处理的。*/
        Stream.of("1", "2", "3", "4", "5", "6", "6")
                .distinct()
                .forEach(System.out::println);

    }

    public static void useCollect() {
        String outPut = Stream.of("1", "2", "3", "4", "5", "6")
                .collect(Collectors.joining(","));
        System.out.println(outPut);


//        流和迭代器类似，只能迭代一次
//        Stream<String> stream = list.stream().map(Person::getName).sorted().limit(10);
//        List<String> newList = stream.collect(Collectors.toList());
//        List<String> newList2 = stream.collect(Collectors.toList());

//        collect(toList()) 可以把流转换为 List 类型

        Stream<String> language = Stream.of("java", "python", "node");

        //Convert a Stream to List
        List<String> result = language.collect(Collectors.toList());

        result.forEach(System.out::println);

//        List newlist = list.stream.collect(toList());
//
//        String outPut = Stream.of("1", "2", "3", "4", "5", "6")
//                .collect(toList());

//
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("1","1");
        map.put("2","2");
        map.put("3","3");
        map.put("4","4");
        map.put("5","5");
        map.put("6","6");
        map.put("7","7");

        list.add(map);

//        list
    }
    public static void main(String[] args) {

        useLimit();

//      stream的执行顺序
//        orderOfExecution();

//        并行流的执行顺序,应该是一起执行的，这个打断点似乎也看不出来
//        orderOfParallelStream();

//        单线程流和并形流的案例
//        compareParallelStreamWithSingleThreadStream();

//        skip和limit合起来用
//        useLimitCombinedWithSkip();



    }


}
